package com.by.rpc.client;

import com.by.log.Logger;
import com.by.log.LoggerFactory;
import com.by.rpc.config.RpcProperties;
import com.by.rpc.dto.ServiceInstance;
import com.by.rpc.registry.ServiceRegistry;
import com.by.rpc.util.KeyUtils;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * RPC引用服务健康检查器。
 * 监听应用启动事件，并在启动完成后定期检查所有RPC引用的服务实例是否可用。
 */
@Component
public class RpcReferenceHealthChecker {
    private static final Logger logger = LoggerFactory.getLogger(RpcReferenceHealthChecker.class);

    // 存储需要检查的 RPC 服务信息
    private static final Map<String, ServiceInfo> rpcServicesToCheck = new ConcurrentHashMap<>();

    // 修复：注入ObjectProvider，不再依赖BeanPostProcessor
    private final ObjectProvider<ServiceRegistry> serviceRegistryProvider;
    private final RpcProperties rpcProperties;

    private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
    private final AtomicBoolean isScheduled = new AtomicBoolean(false);

    /**
     * 修复：更改构造函数以接受新的依赖
     */
    public RpcReferenceHealthChecker(ObjectProvider<ServiceRegistry> serviceRegistryProvider, RpcProperties rpcProperties) {
        this.serviceRegistryProvider = serviceRegistryProvider;
        this.rpcProperties = rpcProperties;
    }

    /**
     * 监听Spring上下文刷新完成事件（通常在应用启动时触发）。
     */
    @EventListener(ContextRefreshedEvent.class)
    public void onApplicationReady() {
        logger.info("Application context refreshed. Starting RPC service health check.");

        // 立即执行一次健康检查
        checkAndLogServices();

        // 如果没有计划任务，则启动一个定时任务
        if (isScheduled.compareAndSet(false, true)) {
            scheduler.scheduleAtFixedRate(this::checkAndLogServices, 5, 30, TimeUnit.SECONDS);
        }
    }

    /**
     * 注册需要检查的RPC服务。
     * 由 RpcReferenceBeanPostProcessor 在注入代理时调用。
     */
    public static void registerRpcService(String beanName, String serviceName, String interfaceName, String version, String group) {
        String key = beanName + ":" + interfaceName;
        rpcServicesToCheck.put(key, new ServiceInfo(serviceName, interfaceName, version, group));
        logger.debug("Registered service for health check: {}", key);
    }

    /**
     * 执行实际的检查和日志记录。
     */
    private void checkAndLogServices() {
        if (rpcServicesToCheck.isEmpty()) {
            return;
        }

        // 修复：直接使用注入的serviceRegistryProvider
        ServiceRegistry serviceRegistry = serviceRegistryProvider.getIfAvailable();
        if (serviceRegistry == null) {
            logger.warn("ServiceRegistry is not yet available, skipping health check.");
            return;
        }

        rpcServicesToCheck.forEach((key, info) -> {
            try {
                String serviceKey = KeyUtils.buildReferenceServiceKey(info.serviceName, info.version, info.group);
                List<ServiceInstance> instances = serviceRegistry.discover(serviceKey);
                if (instances != null && !instances.isEmpty()) {
                    logger.info("Service discovery successful for {}. Found {} instances.", serviceKey, instances.size());
                } else {
                    logger.warn("No instances found for service {} after check.", serviceKey);
                }
            } catch (Exception e) {
                logger.error("Error during scheduled discovery check for service {}: {}", info.serviceName, e.getMessage());
            }
        });
    }

    /**
     * 内部类，用于封装服务信息
     */
    private static class ServiceInfo {
        String serviceName;
        String interfaceName;
        String version;
        String group;

        public ServiceInfo(String serviceName, String interfaceName, String version, String group) {
            this.serviceName = serviceName;
            this.interfaceName = interfaceName;
            this.version = version;
            this.group = group;
        }
    }
}
